﻿#include "CanAnalyzeTest.h"

#include <QtWidgets/QMessageBox>
#include <QtWidgets/QScrollBar>
#include <QtCore/QDebug>
#include <QtCore/QThread>



CanAnalyzeTest::CanAnalyzeTest(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);

	createStatusBar();

	connect(&mReceiveTimer, SIGNAL(timeout()), this, SLOT(timeoutReceive()));

}

void CanAnalyzeTest::createStatusBar()
{
	auto separateLabel = []() {
		QPalette paletteLightGray;
		paletteLightGray.setColor(QPalette::WindowText, Qt::lightGray);
		QLabel * pLabel = new QLabel(tr("|"));
		pLabel->setPalette(paletteLightGray);
		pLabel->setAlignment(Qt::AlignHCenter);
		return pLabel;
	};

	mpLabelStatusTx = new QLabel(tr("发送: 0 Frames 0 Bytes"));
	mpLabelStatusTx->setAlignment(Qt::AlignHCenter);

	mpLabelStatusRx = new QLabel(tr("接收: 0 Frames 0 Bytes"));
	mpLabelStatusRx->setAlignment(Qt::AlignHCenter);

	statusBar()->addPermanentWidget(mpLabelStatusTx);
	statusBar()->addPermanentWidget(separateLabel());

	statusBar()->addPermanentWidget(mpLabelStatusRx);
	//statusBar()->addPermanentWidget(separateLabel());
}

void CanAnalyzeTest::on_btnOpenCan_clicked()
{
	if (ui.btnOpenCan->text() == tr("打开"))
	{
		int iChannelIndex = ui.comboBoxChannel->currentIndex();
		if (iChannelIndex < 0)
		{
			SlotStatusBarMessage(tr("请选择通道"), StatusBarMsgColor_Red);
			return;
		}
		int iBaudRateIndex = ui.comboBoxBaudRate->currentIndex();
		if (iBaudRateIndex < 0)
		{
			SlotStatusBarMessage(tr("波特率"), StatusBarMsgColor_Red);
			return;
		}
		nCANInd = iChannelIndex;

		// 查找can设备
		QString ProductSn[5];
		VCI_BOARD_INFO1 vbi;
		int canDeviceCount = VCI_FindUsbDevice(&vbi);
		if (canDeviceCount <= 0)
		{
			SlotStatusBarMessage(tr("没有找到can设备"), StatusBarMsgColor_Red);
			return;
		}
		for (int i = 0; i < canDeviceCount; i++)
		{
			QString strtemp;
			for (int j = 0; j < 4; j++)
			{
				strtemp += tr("%1").arg(vbi.str_Usb_Serial[i][j]);
			}
			ProductSn[i] = "USBCAN-" + strtemp + "   " + vbi.str_hw_Type;// +"   " + vbi.str_Serial_Num;
			SlotStatusBarMessage(ProductSn[i], StatusBarMsgColor_Blue);
		}
		////////////////////////////////////		
		DWORD dwRel = 0;

		dwRel = VCI_OpenDevice(nDeviceType, nDeviceInd, 0);
		if (dwRel != 1)
		{
			SlotStatusBarMessage(tr("打开设备失败!"), StatusBarMsgColor_Red);
			return;
		}

		VCI_INIT_CONFIG vic;
		vic.AccCode = 0x80000008;
		vic.AccMask = 0xFFFFFFFF;	// 屏蔽码推荐设置为0xFFFFFFFF，即全部接收。
		vic.Filter = 1;
		//vic.Timing0 = 0x00; 
		//vic.Timing1 = 0x14;
		vic.Mode = 0;	// 模式。=0表示正常模式（相当于正常节点），=1表示只听模式（只接收，不影响总线），=2表示自发自收模式（环回模式）。
		QString strBaudRate = ui.comboBoxBaudRate->currentText();
		if ("10Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x31;
			vic.Timing1 = 0x1c;
		}
		else if ("20Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x18;
			vic.Timing1 = 0x1c;
		}
		else if ("40Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x87;
			vic.Timing1 = 0xff;
		}
		else if ("50Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x09;
			vic.Timing1 = 0x1c;
		}
		else if ("80Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x83;
			vic.Timing1 = 0xff;
		}
		else if ("100Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x04;
			vic.Timing1 = 0x1c;
		}
		else if ("125Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x03;
			vic.Timing1 = 0x1c;
		}
		else if ("200Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x81;
			vic.Timing1 = 0xfa;
		}
		else if ("250Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x01;
			vic.Timing1 = 0x1c;
		}
		else if ("400Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x80;
			vic.Timing1 = 0xfa;
		}
		else if ("500Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x00;
			vic.Timing1 = 0x1c;
		}
		else if ("666Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x80;
			vic.Timing1 = 0xb6;
		}
		else if ("800Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x00;
			vic.Timing1 = 0x16;
		}
		else if ("1000Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x00;
			vic.Timing1 = 0x14;
		}
		else if ("1Mbps" == strBaudRate)
		{
			vic.Timing0 = 0x00;
			vic.Timing1 = 0x14;
		}
		else if ("33.33Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x09;
			vic.Timing1 = 0x6f;
		}
		else if ("66.66Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x04;
			vic.Timing1 = 0x6f;
		}
		else if ("83.33Kbps" == strBaudRate)
		{
			vic.Timing0 = 0x03;
			vic.Timing1 = 0x6f;
		}
		else
		{
			VCI_CloseDevice(nDeviceType, nDeviceInd);
			SlotStatusBarMessage(tr("波特率错误"), StatusBarMsgColor_Red);
			return;
		}
#if 0
		int baundRate = 1000;
		switch (baundRate) {
		case 10:
			vic.Timing0 = 0x31;
			vic.Timing1 = 0x1c;
			break;
		case 20:
			vic.Timing0 = 0x18;
			vic.Timing1 = 0x1c;
			break;
		case 40:
			vic.Timing0 = 0x87;
			vic.Timing1 = 0xff;
			break;
		case 50:
			vic.Timing0 = 0x09;
			vic.Timing1 = 0x1c;
			break;
		case 80:
			vic.Timing0 = 0x83;
			vic.Timing1 = 0xff;
			break;
		case 100:
			vic.Timing0 = 0x04;
			vic.Timing1 = 0x1c;
			break;
		case 125:
			vic.Timing0 = 0x03;
			vic.Timing1 = 0x1c;
			break;
		case 200:
			vic.Timing0 = 0x81;
			vic.Timing1 = 0xfa;
			break;
		case 250:
			vic.Timing0 = 0x01;
			vic.Timing1 = 0x1c;
			break;
		case 400:
			vic.Timing0 = 0x80;
			vic.Timing1 = 0xfa;
			break;
		case 500:
			vic.Timing0 = 0x00;
			vic.Timing1 = 0x1c;
			break;
		case 666:
			vic.Timing0 = 0x80;
			vic.Timing1 = 0xb6;
			break;
		case 800:
			vic.Timing0 = 0x00;
			vic.Timing1 = 0x16;
			break;
		case 1000:
			vic.Timing0 = 0x00;
			vic.Timing1 = 0x14;
			break;
		case 33:
			vic.Timing0 = 0x09;
			vic.Timing1 = 0x6f;
			break;
		case 66:
			vic.Timing0 = 0x04;
			vic.Timing1 = 0x6f;
			break;
		case 83:
			vic.Timing0 = 0x03;
			vic.Timing1 = 0x6f;
			break;
		default:
		{
			VCI_CloseDevice(nDeviceType, nDeviceInd);
			SlotStatusBarMessage(tr("波特率错误"), StatusBarMsgColor_Red);
			return;
		} break;
		}
#endif
		dwRel = VCI_InitCAN(nDeviceType, nDeviceInd, nCANInd, &vic);
		if (dwRel != 1)
		{
			VCI_CloseDevice(nDeviceType, nDeviceInd);
			SlotStatusBarMessage(tr("初始化设备失败!"), StatusBarMsgColor_Red);
			return;
		}

		ULONG ulFrameCount = VCI_GetReceiveNum(nDeviceInd, nDeviceInd, nCANInd);

		if (VCI_StartCAN(nDeviceType, nDeviceInd, nCANInd) != 1)
		{
			VCI_CloseDevice(nDeviceType, nDeviceInd);
			SlotStatusBarMessage(tr("启动设备失败!"), StatusBarMsgColor_Red);
			return;
		}

		ui.btnOpenCan->setText(tr("关闭"));

		mbTxDataPause = false;
		ui.btnTxDataPause->setText(tr("暂停接收"));

		mReceiveTimer.start(200);
	}
	else
	{
		VCI_CloseDevice(nDeviceType, nDeviceInd);
		ui.btnOpenCan->setText(tr("打开"));
		mReceiveTimer.stop();
	}
}

void CanAnalyzeTest::on_btnClearTxData_clicked()
{
	ui.editReceive->setPlainText("");
}

void CanAnalyzeTest::on_btnTxDataPause_clicked()
{
	if (ui.btnTxDataPause->text() == tr("暂停接收"))
	{
		mbTxDataPause = true;
		ui.btnTxDataPause->setText(tr("继续接收"));
	}
	else
	{
		mbTxDataPause = false;
		ui.btnTxDataPause->setText(tr("暂停接收"));
	}
}

void CanAnalyzeTest::on_btnSend_clicked()
{
	if (ui.btnOpenCan->text() == tr("打开"))
	{
		SlotStatusBarMessage(tr("请先打开!"), StatusBarMsgColor_Red);
		return;
	}

	QString text = ui.editSend->toPlainText();
	if (text.isEmpty())
	{
		SlotStatusBarMessage(tr("发送内容不能为空"), StatusBarMsgColor_Red);
		return;
	}
	bool bHex = ui.checkBoxSendHex->isChecked();
	QString strCanID = ui.editCanID->text();
	if (strCanID.isEmpty())
	{
		SlotStatusBarMessage(tr("请输出发送CAN ID!"), StatusBarMsgColor_Red);
		return;
	}
	int iCanID = strCanID.toInt();

	QByteArray data;
	if (bHex)
	{// 16进制
		QStringList strHexList;
		for (size_t i = 0; i < text.size();)
		{
			QString str;
			for (int j = 0; j < 2 && i < text.size(); ++j)
			{
				str.append(text.at(i++));
			}
			strHexList.append(str);
		}
		for (size_t i = 0; i < strHexList.size(); ++i)
		{
			bool ok = false;
			data.append(strHexList[i].toInt(&ok, 16));
			if (!ok)
			{
				SlotStatusBarMessage(tr("发送文本非法，不是16进制。"), StatusBarMsgColor_Red);
				return;
			}
		}
	}
	else
	{
		text = text.replace('\n', "\r\n");
		data = text.toLocal8Bit();
	}

	for (size_t i = 0; i < data.size();)
	{
		VCI_CAN_OBJ vco[1];
		vco[0].ID = iCanID;
		vco[0].RemoteFlag = 0;
		vco[0].ExternFlag = 0;
		int iPacketLen = 0;
		for (; iPacketLen < 8 && i < data.size(); )
		{
			vco[0].Data[iPacketLen++] = data[i++];
		}
		vco[0].DataLen = iPacketLen;
		ULONG dwRel = VCI_Transmit(nDeviceType, nDeviceInd, nCANInd, vco, 1);
		if (dwRel <= 0)
		{
			SlotStatusBarMessage(tr("发送失败!"), StatusBarMsgColor_Red);
			break;
		}
		++miTxPacketCount;
		miTxByteCount += iPacketLen;
		//QThread::usleep(1);
	}
	qDebug("miTxPacketCount:%d, miTxByteCount:%d", miTxPacketCount, miTxByteCount);
	this->mpLabelStatusTx->setText(tr("发送: %1 Frames %2 Bytes").arg(miTxPacketCount).arg(miTxByteCount));
}

void CanAnalyzeTest::on_checkBoxSendHex_clicked()
{
	bool bHex = ui.checkBoxSendHex->isChecked();
	qDebug("on_checkBoxSendHex_clicked:%d", bHex);
}

void CanAnalyzeTest::timeoutReceive()
{
	if (mbTxDataPause)
	{
		return;
	}

	bool bHex = ui.checkBoxReceiveHex->isChecked();

	QString msg;
	VCI_CAN_OBJ vco[2500];
	ULONG ulFrameCountRx = VCI_Receive(nDeviceType, nDeviceInd, nCANInd, vco, 2500, 0);
	if (ulFrameCountRx > 0)
	{
		/* 数据处理 */
		for (ULONG i = 0; i < ulFrameCountRx; ++i)
		{
#if 0
			int iFlag = 0;
#endif
			for (BYTE j = 0; j < vco[i].DataLen; ++j)
			{
				mReceiveDataVec.push_back(vco[i].Data[j]);
				if (bHex)
				{// 16进制
					if (j != 0)
					{// 添加空格隔开
						msg.append(' ');
					}
					char szBuf[16] = { 0 };
					_snprintf(szBuf, 16, "%02X", vco[i].Data[j]);
					msg.append(szBuf[0]);
					msg.append(szBuf[1]);
#if 0
					if (vco[i].Data[j] == 0x3A)
					{
						iFlag |= 1;
					}
					if (vco[i].Data[j] == 0x0A)
					{
						iFlag |= 2;
					}
					if (vco[i].Data[j] < '0' || vco[i].Data[j] > '9')
					{
						iFlag |= 4;
					}
#endif
				}
				else
				{
					msg.append(vco[i].Data[j]);
				}
			}
			if (bHex)
			{// 16进制
#if 0
				if (iFlag != 0)
				{
					msg.append(' ');
					msg.append(' ');
					if ((1 & iFlag) > 0)
					{						
						msg.append('#');
					}
					if ((2 & iFlag) > 0)
					{
						msg.append('*');
					}
					if ((4 & iFlag) > 0)
					{
						msg.append('@');
					}
				}
#endif
				msg.append("\r\n");
			}

			++miRxPacketCount;
			miRxByteCount += vco[i].DataLen;
		}
		this->mpLabelStatusRx->setText(tr("接收: %1 Frames %2 Bytes").arg(miRxPacketCount).arg(miRxByteCount));
	}
	else if (ulFrameCountRx == -1)
	{
		/* USB-CAN设备不存在或USB掉线，可以调用VCI_CloseDevice并重新VCI_OpenDevice。如此可以达到USB-CAN设备热插拔的效果。 */
		return;
	}

	if (msg.isEmpty())
	{
		return;
	}

#if 0
	{// IMU数据包解析		
		auto funcParseData = [](std::vector<unsigned char> &ReceiveDataVec)
		{
			auto GetUInt16 = [](uint8_t highByte, uint8_t lowByte)->uint16_t
			{
				return (uint16_t)((((uint16_t)highByte) << 8) | (((uint16_t)lowByte) << 0));
			};
			auto GetUInt16Ex = [&](std::vector<unsigned char> &ReceiveDataVec, uint32_t index)->uint16_t
			{
				uint8_t lByte = ReceiveDataVec[index];
				uint8_t hByte = ReceiveDataVec[index + 1];
				return GetUInt16(hByte, lByte);
			};
			//==========================================================================

			if (ReceiveDataVec.size() >= 11)
			{
				// 要释放字节长度
				uint32_t releaseDataLen = 0;
				int i3APos = -1;
				for (uint32_t i = 0; i < ReceiveDataVec.size(); ++i)
				{
					if (0x3A != ReceiveDataVec[i])
					{
						continue;
					}
					//qDebug("%d -> 0x3A\r\n", i);
					// 释放包头之前的所有数据
					if (i > 0)
					{
						releaseDataLen = i;
					}
					//
					i3APos = i;
					//
					if (ReceiveDataVec.size() - i < 11)
					{   // 不满足最小包长度
						break;
					}
					// 读取长度
					uint16_t iPacketDataLen = GetUInt16Ex(ReceiveDataVec, i + 5);
					 // 判断长度是否异常
					if (iPacketDataLen > 100)
					{
						iPacketDataLen = 0;
						i3APos = -1;
						continue;
					}
					if (ReceiveDataVec.size() - i < 11 + iPacketDataLen)
					{   // 不满足包长度
						break;
					}
					// 判断结尾
					if (0x0D != ReceiveDataVec[i + iPacketDataLen + 9]
						|| 0x0A != ReceiveDataVec[i + iPacketDataLen + 10])
					{   // 结尾不正确，有可能当前包头0x3A不是真包头，只是数据中间部分
						iPacketDataLen = 0;
						i3APos = -1;
						continue;
					}
					// 读取LRC校验
					uint16_t LRCVal = GetUInt16Ex(ReceiveDataVec, i + iPacketDataLen + 7);//(((uint16_t)hByte) << 8) | (((uint16_t)lByte) << 0);
																							   // 计算LRC值
					uint16_t sum = 0;
					for (uint8_t m = 1; m <= 6 + iPacketDataLen; ++m)
					{
						sum += ReceiveDataVec[i + m];
					}
					if (sum != LRCVal)
					{   // 校验和不正确
						// 丢弃这个包
						releaseDataLen = i + iPacketDataLen + 10 + 1;
						qDebug() << "检验和错误:" << sum << " != " << LRCVal << ", iPacketDataLen:" << iPacketDataLen;
						iPacketDataLen = 0;
						i3APos = -1;
						continue;
					}
					// 读取命令
					uint16_t iCommand = ReceiveDataVec[i + 3];
					qDebug() << "iCommand:" << iCommand;

					// 包处理完，可以丢弃
					releaseDataLen = i + iPacketDataLen + 10 + 1;
					// 设置i值到包0x0A
					i = i + iPacketDataLen + 10;
					// 重置当前包数据
					iPacketDataLen = 0;
					i3APos = -1;
				}
				if (releaseDataLen > 0)
				{
					std::vector<unsigned char> ReceiveDataVecNew(ReceiveDataVec.size() - releaseDataLen);
					for (size_t i = releaseDataLen; i < ReceiveDataVecNew.size(); ++i)
					{
						ReceiveDataVecNew[i - releaseDataLen] = ReceiveDataVec[i];
					}
					ReceiveDataVec.swap(ReceiveDataVecNew);
				}
			}
		};
		funcParseData(mReceiveDataVec);
	}
#endif

#if 0
	if (miEditTextLength > 10000 * 1000)
	{// 截断过长数据
		QString strTextTmp = ui.editReceive->toPlainText();
		int iHalfIndex = strTextTmp.indexOf('\n', strTextTmp.size() / 2);
		if (iHalfIndex != -1)
		{
			++iHalfIndex;

			strTextTmp = strTextTmp.right(strTextTmp.size() - iHalfIndex);
			ui.editReceive->setPlainText(strTextTmp);
			miEditTextLength = strTextTmp.size();

			ui.editReceive->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
			//int iScrollVal = ui.editReceive->verticalScrollBar()->value();
			int iScrollMax = ui.editReceive->verticalScrollBar()->maximum();
			ui.editReceive->verticalScrollBar()->setValue(iScrollMax);
		}
}
#endif
	// 添加文本，appendPlainText似乎时自动再末尾分行
	mstrPortData += msg;

#if 1
	int sliderPosition = 0;
	int iScrollMax = 0;
	// 读取滚动条原来位置
	if (QScrollBar * pVerticalScrollBar = ui.editReceive->verticalScrollBar())
	{
		sliderPosition = pVerticalScrollBar->sliderPosition();
		iScrollMax = pVerticalScrollBar->maximum();
		//qDebug() << "sliderPosition:" << sliderPosition << "  iScrollMax:" << iScrollMax;
	}
	// 光标移动到末尾
	ui.editReceive->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
	ui.editReceive->insertPlainText(mstrPortData);
	miEditTextLength += mstrPortData.size();
	mstrPortData.clear();

	if (iScrollMax - sliderPosition < 5)
	{
		// 靠近末尾时，光标移动到末尾
		//sliderPosition有时总会小于iScrollMax，很可能是窗口高度的问题，光标移到末尾可能并不是设置滚动条到最大值
		//ui.editReceive->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
		if (QScrollBar * pVerticalScrollBar = ui.editReceive->verticalScrollBar())
		{
			int iScrollMaxNew = pVerticalScrollBar->maximum();
			if (iScrollMaxNew > 0)
			{
				pVerticalScrollBar->setSliderPosition(iScrollMaxNew);
				//qDebug() << "setSliderPosition: Max";
			}
		}
	}
	else
	{
		if (QScrollBar * pVerticalScrollBar = ui.editReceive->verticalScrollBar())
		{
			int iScrollMaxNew = pVerticalScrollBar->maximum();
			if (iScrollMaxNew > 0 && sliderPosition != iScrollMax && iScrollMax != 0)
			{
				// 设置当前滚动条为原来位置
				pVerticalScrollBar->setSliderPosition(sliderPosition);
				//qDebug() << "setSliderPosition keep position";
			}
		}
	}


#else
	int iFindPos = mstrPortData.lastIndexOf('\n');
	if (iFindPos != -1)
	{
		QString strShow = mstrPortData.left(iFindPos + 1);
		if (iFindPos + 1 == mstrPortData.size())
		{
			mstrPortData.clear();
		}
		else
		{
			mstrPortData = mstrPortData.right(mstrPortData.size() - (iFindPos + 1));
		}
		ui.editReceive->appendPlainText(strShow);
		miEditTextLength += strShow.size();
		qDebug() << strShow;
	}
#endif
}


void CanAnalyzeTest::SlotStatusBarMessage(QString strMessage, StatusBarMsgColor iLevel, int iTimeoutMs)
{
	qDebug() << strMessage;
	QString strSheet;
	switch (iLevel)
	{
	case StatusBarMsgColor_Black:
		strSheet = "QStatusBar{color: black;font-size: 12px;}";
		break;
	case StatusBarMsgColor_Green:
		strSheet = "QStatusBar{color: green;font-size: 12px;}";
		break;
	case StatusBarMsgColor_Blue:
		strSheet = "QStatusBar{color: blue;font-size: 12px;}";
		break;
	case StatusBarMsgColor_Red:
		strSheet = "QStatusBar{color: red;font-size: 12px;}";
		QApplication::beep();
		break;
	default:
		strSheet = "QStatusBar{color: black;font-size: 12px;}";
		break;
	}
	statusBar()->setStyleSheet(strSheet);
	ui.statusBar->showMessage(strMessage, iTimeoutMs);
}

void CanAnalyzeTest::wheelEvent(QWheelEvent *event)
{
	BOOL bCtrl = ::GetKeyState(VK_CONTROL) & 0x8000;
	if (bCtrl)
	{
		if (ui.editReceive->hasFocus())
		{
			const QFont fontOld = ui.editReceive->font();
			QFont fontNew = fontOld;
			fontNew.setPointSize(fontOld.pointSize() + (event->delta() > 0 ? 5 : -5));
			ui.editReceive->setFont(fontNew);

			event->ignore();
		}
		else if (ui.editSend->hasFocus())
		{
			const QFont fontOld = ui.editSend->font();
			QFont fontNew = fontOld;
			fontNew.setPointSize(fontOld.pointSize() + (event->delta() > 0 ? 5 : -5));
			ui.editSend->setFont(fontNew);

			event->ignore();
		}
	}
}
